/*
 * qWikiOffice Desktop 1.0 Copyright(c) 2007-2008, Integrated Technologies, Inc.
 * licensing@qwikioffice.com
 * 
 * http://www.qwikioffice.com/license
 * 
 * NOTE: This code is based on code from the original Ext JS desktop demo. I
 * have made many modifications/additions.
 * 
 * The Ext JS licensing can be viewed here:
 * 
 * Ext JS Library 2.0 Beta 2 Copyright(c) 2006-2007, Ext JS, LLC.
 * licensing@extjs.com
 * 
 * http://extjs.com/license
 * 
 */

Ext.app.App = function(config) {
	Ext.apply(this, config);

	this.addEvents({
				'ready' : true,
				'beforeunload' : true,
				'moduleactioncomplete' : true
			});

	Ext.onReady(this.initApp, this);
};

Ext.extend(Ext.app.App, Ext.util.Observable, {
			/**
			 * @cfg {Object} A config object to be applied to Ext.Desktop.
			 */
			desktopConfig : null,
			/**
			 * @cfg {Object} The member info. Example: { group: 'demo', name:
			 *      'Todd Murdock' }
			 */
			memberInfo : null,
			/**
			 * @cfg {Array} An array of the module definitions. The definitions
			 *      are used until the module is loaded on demand. * Example: [ {
			 *      "id": "demo-accordion", "type": "demo/accordion",
			 *      "className": "QoDesk.AccordionWindow", "launcher": {
			 *      "iconCls":"acc-icon", "shortcutIconCls":"demo-acc-shortcut",
			 *      "text":"Accordion Window", "tooltip":"A window with an
			 *      accordion layout" }, "launcherPaths": { "StartMenu": "/" } },
			 *      ...
			 */
			modules : null,

			/**
			 * module javascript root url
			 * 
			 * @type
			 */
			modulesUrlRoot : null,

			/**
			 * @cfg {Object/Array}
			 */
			plugins : null,
			/**
			 * @cfg {Object} The members privileges. * Example: {
			 *      "qo-preferences": { "viewThemes": 1, "viewWallpapers": 1 },
			 *      "demo-layout":1, "demo-grid":1, "demo-bogus":1,
			 *      "demo-tabs":1, "demo-accordion":1 }
			 */
			privileges : null,
			/**
			 * Read-only. This app's ready state
			 * 
			 * @type boolean
			 */
			isReady : false,
			/**
			 * Read-only. The url of this app's server connection
			 * 
			 * Allows a module to connect to its server script without knowing
			 * the path. Example ajax call:
			 * 
			 * Ext.Ajax.request({ url: this.moduleScripter(m), // Could also
			 * pass the module id in the querystring like this. // url:
			 * this.app.connection+'?id='+this.id, params: { id: this.id ... },
			 * success: function(){ ... }, failure: function(){ ... }, scope:
			 * this });
			 */
			moduleScripter : function(m) {
				return m.script;
			},

			/**
			 * Read-only. The queue of requests to run once a module is loaded
			 */
			requestQueue : [],

			init : Ext.emptyFn,

			initApp : function() {
				//设置当前的APP到Ext上下文。
				Ext.CUR_APP=this;
				this.init();
				this.preventBackspace();

				// the user interface
				this.desktop = new Ext.Desktop(Ext.applyIf({
							app : this
						}, this.desktopConfig));

				// init plugins
				if (this.plugins) {
					if (Ext.isArray(this.plugins)) {
						for (var i = 0, len = this.plugins.length; i < len; i++) {
							this.plugins[i] = this.initPlugin(this.plugins[i]);
						}
					} else {
						this.plugins = this.initPlugin(this.plugins);
					}
				}

				Ext.EventManager.on(window, 'beforeunload', this.onBeforeUnload, this);
				this.fireEvent('ready', this);
				this.isReady = true;
			},

			initPlugin : function(p) {
				if (p.ptype && !Ext.isFunction(p.init)) {
					p = Ext.ComponentMgr.createPlugin(p);
				} else if (Ext.isString(p)) {
					p = Ext.ComponentMgr.createPlugin({
								ptype : p
							});
				}
				p.init(this);
				return p;
			},

			/**
			 * @param {string}
			 *            v The id or moduleType you want returned
			 * @param {Function}
			 *            cb The Function to call when the module is
			 *            ready/loaded
			 * @param {object}
			 *            scope The scope in which to execute the function
			 */
			requestModule : function(v, cb, scope) {
				var m = this.getModule(v);
				if (m) {
					if (m.loaded === true) {
						cb.call(scope, m);
					} else {
						if (cb && scope) {
							this.requestQueue.push({
										id : m.id,
										callback : cb,
										scope : scope
									});
							this.loadModule(m);
						}
					}
				}
			},

			/**
			 * @param {Ext.app.Module}
			 *            m The module
			 */
			loadModule : function(m) {
				if (m.isLoading) {
					return false;
				}

				var id = m.id;
				var moduleName = m.launcher.text;

				var notifyWin = this.desktop.showNotification({
							html : '正载入模块' + moduleName + '...',
							title : '信息提示'
						});

				m.isLoading = true;

				Ext.Ajax.request({
							timeout: 30000,
							disableCaching:true,
							method: "GET",
							url : this.getModuleUrl(m),
							params : {
								moduleId : id
							},
							success : function(o) {
								notifyWin.setIconClass('x-icon-done');
								notifyWin.setTitle('信息提示');
								notifyWin.setMessage(moduleName + '已载入.');
								this.desktop.hideNotification(notifyWin);
								notifyWin = null;
			
									if (o.responseText !== '') {
										eval(o.responseText);
										this.loadModuleComplete(true, id);
									} else {
										m.isLoading = false;
										Ext.MessageBox.alert('出错提示', '系统没有查询到相关的模块信息!');
									}
							},
							failure : function() {
								m.isLoading = false;
								Ext.MessageBox.alert('出错提示', '访问该系统模块发生错误!');
							},
							scope : this
						});

				return true;
			},

			/**
			 * @param {boolean}
			 *            success
			 * @param {string}
			 *            id
			 * 
			 * Will be called when a module is loaded. If a request for this
			 * module is waiting in the queue, it as executed and removed from
			 * the queue.
			 */
			loadModuleComplete : function(success, id) {
				if (success === true && id) {
					var p = this.getModule(id); // get the placeholder
					var m = this.instantiateModule(p);
          
					if (m) {
						m.isLoading = false;
						m.loaded = true;
						m.init(p.initParams);
						m.on('actioncomplete', this.onModuleActionComplete, this);

						var q = this.requestQueue;
						var nq = [];
						var found = false;

						for (var i = 0, len = q.length; i < len; i++) {
							if (found === false && q[i].id === id) {
								found = q[i];
							} else {
								nq.push(q[i]);
							}
						}

						this.requestQueue = nq;

						if (found) {
							found.callback.call(found.scope, m);
						}
						return m;
					}
				}
				return null;
			},

			/**
			 * Private
			 * 
			 * @param {module}
			 *            object
			 */
			instantiateModule : function(module) {

				if (module && module.loaded === false) {
					if (eval('typeof ' + module.className) === 'function') {
						var m = eval('new ' + module.className + '()');
						m.app = this;
            m.id=module.id;
						var ms = this.modules;
						for (var i = 0, len = ms.length; i < len; i++) {
							if (ms[i].id === m.id) {
								Ext.apply(m, ms[i]);
								ms[i] = m;
							}
						}

						return m;
					}
				}
				return null;
			},

			/**
			 * @param {string}
			 *            v The id or moduleType you want returned
			 */
			getModule : function(v) {
				var ms = this.modules;

				for (var i = 0, len = ms.length; i < len; i++) {
					if (ms[i].id == v || ms[i].moduleType == v) {
						return ms[i];
					}
				}

				return null;
			},

			/**
			 * private
			 * 
			 * @param {}
			 *            m
			 * @return {} module script url
			 */
			getModuleUrl : function(m) {
				if (m.scriptUrl) {
					return m.scriptUrl;
				} else {
					var subUrl = "/" + m.id + "/" + m.id + ".js";
					return this.modulesUrlRoot ? this.modulesUrlRoot + subUrl : subUrl;
				}
			},
			/**
			 * @param {Ext.app.Module}
			 *            m The module to register
			 */
			registerModule : function(m) {
				if (!m) {
					return false;
				}
				this.modules.push(m);
				m.launcher.handler = this.desktop.launchWindow.createDelegate(this.desktop, [m.id]);
				m.app = this;
				return true;
			},

			/**
			 * @param {string}
			 *            id or moduleType
			 * @param {array}
			 *            requests An array of request objects
			 * 
			 * Example: this.app.makeRequest('module-id', { requests: [ {
			 * method: 'createWindow', params: '', callback:
			 * this.myCallbackFunction, scope: this }, { ... } ] });
			 */
			makeRequest : function(id, params, cb, scope) {
				if (id !== '') {
					var m = this.requestModule(id, function(m) {
								if (m) {
									if (params) {
										params["desktopModule"] = m;
									} else {
										params = {
											"desktopModule" : m
										};
									}

									m.createWindow(params);
									if (cb) {
										cb.call(scope || this, m);
									}
								}
							}, this);
				}
			},

			showNotice : function(notice, delay) {
				var notifyWin = this.desktop.showNotification(notice);
				var noticeObj = Ext.get(notice.uecId);
				noticeObj.on("click", function() {
							notice.callback.call(this, notifyWin, notice.id);
							notifyWin.close();
						}, this);
				this.desktop.hideNotification(notifyWin, delay);
			},

			/**
			 * @param {string}
			 *            method The module method
			 * @param {string}
			 *            id The module id property
			 */
			isAllowedTo : function(method, id) {
				if (method !== '' && id != '') {
					var p = this.privileges;
					if (p[id] && p[id][method] && p[id][method] === 1) {
						return true;
					}
				}
				return false;
			},

			getDesktop : function() {
				return this.desktop;
			},

			/**
			 * @param {Function}
			 *            fn The function to call after the app is ready
			 * @param {object}
			 *            scope The scope in which to execute the function
			 */
			onReady : function(fn, scope) {
				if (!this.isReady) {
					this.on('ready', fn, scope);
				} else {
					fn.call(scope, this);
				}
			},

			onBeforeUnload : function(e) {
				if (this.fireEvent('beforeunload', this) === false) {
					e.stopEvent();
				}
			},

			/**
			 * Prevent the backspace (history -1) shortcut
			 */
			preventBackspace : function() {
				var map = new Ext.KeyMap(document, [{
									key : Ext.EventObject.BACKSPACE,
									stopEvent : false,
									fn : function(key, e) {
										var t = e.target.tagName;
										if (t != "INPUT" && t != "TEXTAREA") {
											e.stopEvent();
										}
									}
								}]);
			},

			/**
			 * @param {Ext.app.Module}
			 *            module
			 * @param {object}
			 *            data
			 * @param {object}
			 *            options
			 * 
			 * It may be benificial for a system module to register all (or
			 * some) module activity in the database.
			 * 
			 * Example usage:
			 * 
			 * this.app.on('moduleactioncomplete', this.onModuleActionComplete,
			 * this);
			 * 
			 * onModuleActionComplete : function(app, module, params, options){
			 * if(module && params){
			 * 
			 * if(typeof options === 'object'){ var keepExisting =
			 * options.keepExisting || false; }
			 * 
			 * Ext.Ajax.request({ url: this.app.connection , params: { action:
			 * 'registerModuleAction' , id: this.id , actionModuleId: module.id ,
			 * actionData: typeof params.data == 'object' ?
			 * Ext.encode(params.data) : params.data , actionDesc:
			 * params.description , keepExisting: keepExisting || false } ,
			 * failure: function(response,options){ // failed } , success:
			 * function(o){ // success } , scope: this }); } }
			 */
			onModuleActionComplete : function(module, data, options) {
				this.fireEvent('moduleactioncomplete', this, module, data, options);
			}
		});